package com.panfeng.xcloud.boss.provider.member.service.impl;

import com.alibaba.fastjson.JSON;
import com.huobi.api.service.account.AccountAPIServiceImpl;
import com.panfeng.xcloud.boss.provider.enums.AccountBizTypeEnum;
import com.panfeng.xcloud.boss.provider.enums.AccountTransTypeEnum;
import com.panfeng.xcloud.boss.provider.enums.AccountTypeEnum;
import com.panfeng.xcloud.boss.provider.member.dao.mapper.UserAccountMapperExt;
import com.panfeng.xcloud.boss.provider.member.dao.mapper.UserBaseMapperExt;
import com.panfeng.xcloud.boss.provider.member.dao.mapper.UserExchangePwdMapperExt;
import com.panfeng.xcloud.boss.provider.member.dao.mapper.WalletCurrencyMapperExt;
import com.panfeng.xcloud.boss.provider.member.dto.request.*;
import com.panfeng.xcloud.boss.provider.member.dto.response.GetExchangeSupportCoinsRespDTO;
import com.panfeng.xcloud.boss.provider.member.enums.ExchangePwdTypeEnum;
import com.panfeng.xcloud.boss.provider.member.enums.ExchangeTypeEnum;
import com.panfeng.xcloud.boss.provider.member.enums.UserAccountStatusEnum;
import com.panfeng.xcloud.boss.provider.member.service.IExchangeBindingHuobiService;
import com.panfeng.xcloud.boss.provider.member.service.ISeqenceService;
import com.panfeng.xcloud.boss.provider.member.service.IUserSMSService;
import com.panfeng.xcloud.boss.provider.member.web.vo.response.GetApiInfoRespVO;
import com.panfeng.xcloud.boss.provider.member.web.vo.response.GetSupportCoinsRespVO;
import com.panfeng.xcloud.boss.provider.member.web.vo.response.HuobiPwdRespVO;
import com.panfeng.xcloud.common.core.configuration.DataDictionaryConfig;
import com.panfeng.xcloud.common.core.constants.RabbitMQConstant;
import com.panfeng.xcloud.common.core.enums.DataDictionaryTypeEnum;
import com.panfeng.xcloud.common.core.enums.ResponseStatusEnum;
import com.panfeng.xcloud.common.core.exceptions.BaseBizException;
import com.panfeng.xcloud.common.core.utils.DES3Util;
import com.panfeng.xcloud.common.core.utils.StringUtils;
import com.panfeng.xcloud.common.core.web.vo.ExchangeBindingMqVo;
import com.panfeng.xcloud.common.core.web.vo.ExchangeUnBindingMqVo;
import com.panfeng.xcloud.dao.member.entity.UserAccount;
import com.panfeng.xcloud.dao.member.entity.UserBase;
import com.panfeng.xcloud.dao.member.entity.UserExchangePwd;
import com.panfeng.xcloud.dao.member.mapper.UserAccountMapper;
import com.panfeng.xcloud.dao.member.mapper.UserExchangePwdMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author xiaobo
 */
@Transactional(rollbackFor = Exception.class)
@Service
@Slf4j
public class ExchangeBindingHuobiServiceImpl implements IExchangeBindingHuobiService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserExchangePwdMapper userExchangePwdMapper;

    @Value("${xdcloud.des3.secret-key}")
    private String secrectKey;

    @Autowired
    private UserAccountMapperExt userAccountMapperExt;

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private ISeqenceService iSeqenceService;

    @Autowired
    private UserExchangePwdMapperExt userExchangePwdMapperExt;

    @Autowired
    private IUserSMSService iUserSMSService;

    @Autowired
    private DataDictionaryConfig dataDictionaryConfig;

    @Autowired
    private WalletCurrencyMapperExt walletCurrencyMapperExt;

    @Autowired
    private UserBaseMapperExt userBaseMapperExt;

    @Resource
    private AmqpTemplate amqpTemplate ;

    @Override
    public boolean huobiVerify(HuobiVerifyReqDTO reqBean) {
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());

        AccountAPIServiceImpl accountService = new AccountAPIServiceImpl(reqBean.getApiKey(), reqBean.getSecretKey(),restHost);

        accountService.getSwapAccountInfo("");

        return true;
    }

    @Override
    public boolean reHuobiBinding(HuobiBindingReqDTO reqBean) {
        //huobi verify
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
        String websocketHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_websocket_host.getCode());

        //判断是否是第一次创建账户,如果是: 创建对应账户
        List<UserAccount> userAccounts = this.userAccountMapperExt.queryExchangeAccountByUserId(reqBean.getUserId(), ExchangeTypeEnum.HUOBI.code,reqBean.getBizType());
            log.info("已经绑定huobi账户,进行更新");
            if (userAccounts.size()>1){
                log.error(">>> 该账户绑定多个huobi账户,账户为为:{} <<<", JSON.toJSONString(userAccounts));
                throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
            }
            UserAccount userAccount = userAccounts.get(0);
            int accountTransType = userAccount.getAccountTransType();
//            //BINDED_ERROR 同一账号不能同时绑定跟单和发单
//            if (accountTransType != reqBean.getAccountTransType()){
//                throw new BaseBizException(ResponseStatusEnum.BINDED_ERROR);
//            }
            List<UserExchangePwd> userPwds = userExchangePwdMapperExt.queryByUserId(userAccount.getUserId(), ExchangeTypeEnum.HUOBI.code);

            if (userPwds.size()!=2){
                log.error(">>> huobi密码获取失败,获取密码为:{} <<<", JSON.toJSONString(userPwds));
                throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
            }
            for (UserExchangePwd pwd : userPwds){
                Integer pwdType = pwd.getPwdType();
                String salt = pwd.getSalt();
                if (ExchangePwdTypeEnum.secretKey.code==pwdType){
                    int rs = this.userExchangePwdMapperExt.updatePwd(userAccount.getUserId(), DES3Util.doubleEncode(reqBean.getSecretKey(), secrectKey, salt), ExchangePwdTypeEnum.secretKey.code, ExchangeTypeEnum.HUOBI.code);
                    if (rs<=0){
                        log.error(">>> 更新失败 <<<");
                        throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
                    }
                }else if (ExchangePwdTypeEnum.apiKey.code==pwdType){
                    int rs = this.userExchangePwdMapperExt.updatePwd(userAccount.getUserId(), DES3Util.doubleEncode(reqBean.getApiKey(), secrectKey, salt), ExchangePwdTypeEnum.apiKey.code, ExchangeTypeEnum.HUOBI.code);
                    if (rs<=0){
                        log.error(">>> 更新失败 <<<");
                        throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
                    }
                }
            }
        ExchangeBindingMqVo.ExchangeBindingMqVoBuilder bindingMqVoBuilder = ExchangeBindingMqVo.builder();
        bindingMqVoBuilder.type(1).accountId(userAccount.getAccountId()).userId(userAccount.getUserId()).apiKey(reqBean.getApiKey())
                .exchangeType(ExchangeTypeEnum.HUOBI.code).secretKey(reqBean.getSecretKey());
        try {
            log.info("重新绑定正在发送消息队列:{}", RabbitMQConstant.EXCHANGE_BINDING_QUEUE);
            amqpTemplate.convertAndSend(RabbitMQConstant.EXCHANGE_BINDING_QUEUE, bindingMqVoBuilder.build());
            log.info("发送消息成功");
        } catch (AmqpException e) {
            log.info("发送消息失败,内容为:{}",JSON.toJSONString(bindingMqVoBuilder.build()));
            e.printStackTrace();
        }
            return true;
    }

    @Override
    @Transactional
    public boolean huobiBinding(HuobiBindingReqDTO reqBean) {

        //判断绑定手机号
        UserBase userBase = userBaseMapperExt.queryUserInfo(reqBean.getUserId());
        if (null == userBase){
            throw new BaseBizException(ResponseStatusEnum.GET_CURRENT_LOGIN_INFO_FAIL);
        }

        String mobile = userBase.getMobile();


        if ( StringUtils.isEmpty(mobile) ){
            throw new BaseBizException(ResponseStatusEnum.MOBILE_BINDING_ERROR);
        }

        try {
            //判断是否是第一次创建账户,如果是: 创建对应账户
            List<UserAccount> userAccounts = this.userAccountMapperExt.queryExchangeAccountByUserId(reqBean.getUserId(), ExchangeTypeEnum.HUOBI.code,reqBean.getBizType());
            log.info("查询到HUOBI绑定账号数量为: "+userAccounts.size());
            //未绑定账户需要重新创建账户并进行绑定
            if (userAccounts.size() ==0){
//                if (StringUtils.isEmpty(reqBean.getCoins())){
//                    log.error(">>>新增绑定账户时,选择币种为空<<<");
//                    throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
//                }

                UserAccount account = new UserAccount();
                account.setAccountType(AccountTypeEnum.REAL.getCode());
                account.setAccountTransType(reqBean.getAccountTransType());
                account.setAccountBizType(AccountBizTypeEnum.CONSTRACT_TRADE.getCode());
                account.setAccountNickname("HUOBI合约");
                account.setAccountRating("D");
                account.setUserId(reqBean.getUserId());
                if (AccountTransTypeEnum.PUBLISH.getCode()==account.getAccountTransType()){
                    //设置状态正在审核中
                    account.setStatus(UserAccountStatusEnum.under_review.code);
                }else {
                    account.setStatus(UserAccountStatusEnum.nomal.code);
                }

                account.setExchangeType(ExchangeTypeEnum.HUOBI.code);
                account.setAccountNumber(userAccountMapperExt.queryAccountNumber(reqBean.getUserId()));
                String accountId = iSeqenceService.gainAccountId();
                account.setAccountId(accountId);
                if (!StringUtils.isEmpty(reqBean.getCoins())){
                    account.setSupportCoins(reqBean.getCoins());
                }
                int rs = userAccountMapper.insertSelective(account);

                if(rs > 0){
                    log.info(">>> 新增(老的账户体系)账号addOldAccountInfo账号成功 <<<");
                }else{
                    log.error(">>> 新增(老的账户体系)账号addOldAccountInfo账号失败 <<<");
                    throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
                }

                //插入秘钥
                UserExchangePwd.UserExchangePwdBuilder builder = UserExchangePwd.builder();

                String iv = DES3Util.getRandomIv();
                UserExchangePwd exchangePwd = builder.accountId(accountId).accountTransType(reqBean.getAccountTransType()).exchangeType(ExchangeTypeEnum.HUOBI.code)
                        .pwdType(ExchangePwdTypeEnum.secretKey.code).pwd(DES3Util.doubleEncode(reqBean.getSecretKey(), secrectKey, iv))
                        .salt(iv).status(0).userId(reqBean.getUserId()).build();
                int insert = this.userExchangePwdMapper.insert(exchangePwd);
                if(insert > 0){
                    log.info(">>> 新增secrectKey成功 <<<");
                }else{
                    log.error(">>> 新增secrectKey失败 <<<");
                    throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
                }

                String iv2 = DES3Util.getRandomIv();
                UserExchangePwd apikeyExchangePwd = builder.pwd(reqBean.getApiKey()).pwdType(ExchangePwdTypeEnum.apiKey.code).salt(iv2).pwd(DES3Util.doubleEncode(reqBean.getApiKey(), secrectKey, iv2)).build();
                int insert1 = this.userExchangePwdMapper.insert(apikeyExchangePwd);
                if(insert1 > 0){
                    log.info(">>> 新增apikey成功 <<<");
                }else{
                    log.error(">>> 新增apikey失败 <<<");
                    throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
                }
                return true;

            }else {
                log.error(">>>已存在绑定账号,新增账号失败 <<<");
                throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    @Override
    public HuobiPwdRespVO getUserHuobiPwd(String userId) {
        List<UserExchangePwd> userExchangePwds = userExchangePwdMapperExt.queryByUserId(userId, ExchangeTypeEnum.HUOBI.code);
        HuobiPwdRespVO respVO = new HuobiPwdRespVO();
        for (UserExchangePwd exchangePwd : userExchangePwds){
            String salt = exchangePwd.getSalt();
            Integer pwdType = exchangePwd.getPwdType();
            String pwd = exchangePwd.getPwd();
            String decode = DES3Util.doubleDecode(pwd, secrectKey, salt);
            if (ExchangePwdTypeEnum.secretKey.code==pwdType){
                respVO.setSecretKey(decode);
            }else if (ExchangePwdTypeEnum.apiKey.code==pwdType){
                respVO.setApiKey(decode);
            }else {
                respVO.setPassphrase(decode);
            }

        }
        return respVO;
    }

    @Override
    public boolean huobiUnbind(HuobiUnbindReqDTO huobiUnbindReqDTO) {
        List<UserAccount> userAccounts = this.userAccountMapperExt.queryExchangeAccountByUserId(huobiUnbindReqDTO.getUserId(), ExchangeTypeEnum.HUOBI.code, AccountBizTypeEnum.CONSTRACT_TRADE.getCode());
        if (userAccounts.size() > 1){
            log.info(">>>>> 解绑huobi账户,发现绑定多个(非1个)HUOBI账户,数据为:{}<<<<<",JSON.toJSONString(userAccounts));
            throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
        }

        if(userAccounts.size() == 0){
            log.info(">>>>> 解绑huobi账户,发现无有效的HUOBI账户,数据为:{}<<<<<",JSON.toJSONString(userAccounts));
            throw new BaseBizException(ResponseStatusEnum.DATA_NOT_EXIST_OPERATE_FAIL);
        }

        UserAccount userAccount = userAccounts.get(0);

        CheckVerifyCodeReqDTO checkVerifyCodeReqDTO = new CheckVerifyCodeReqDTO(huobiUnbindReqDTO.getAccountId(), huobiUnbindReqDTO.getVerifyCode(), huobiUnbindReqDTO.getBusinessType());
        boolean res = iUserSMSService.checkVerifyCode(checkVerifyCodeReqDTO);
        if (!res) {
            log.info(">>>>> 解绑huobi账户，校验验证码错误 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
        }

        UserAccount u = new UserAccount();
        u.setStatus(UserAccountStatusEnum.expire.code);
        u.setModifyTime(new Date());
        u.setId(userAccount.getId());

        //对账户进行逻辑删除
        int rs= this.userAccountMapper.updateByPrimaryKeySelective(u);
        if (rs <=0) {
            log.info(">>>>> 解绑huobi账户，userAccountMapper.updateByPrimaryKeySelective错误 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
        }

        //对huobi秘钥数据进行物理删除
        List<UserExchangePwd> userPwds = userExchangePwdMapperExt.queryByUserId(userAccount.getUserId(), ExchangeTypeEnum.HUOBI.code);
        for (UserExchangePwd userExchangePwd : userPwds){
            int rs1 = this.userExchangePwdMapper.deleteByPrimaryKey(userExchangePwd.getId());
            if (rs1 <=0) {
                log.info(">>>>> 解绑huobi账户，userExchangePwdMapper.deleteByPrimaryKey错误 <<<<<");
                throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
            }
        }
        ExchangeUnBindingMqVo unBindingMqVo = new ExchangeUnBindingMqVo();
        unBindingMqVo.setAccountId(u.getAccountId());
        try {
            log.info("解除绑定正在发送消息队列:{}", RabbitMQConstant.EXCHANGE_UNBINDING_QUEUE);
            amqpTemplate.convertAndSend(RabbitMQConstant.EXCHANGE_UNBINDING_QUEUE, unBindingMqVo);
            log.info("发送消息成功");
        } catch (AmqpException e) {
            log.info("发送消息失败,内容为:{}",JSON.toJSONString(unBindingMqVo));
            e.printStackTrace();
        }
        return true;
    }


    @Override
    public boolean updateSupportCoins(UpdateSupportCoinsReqDTO updateSupportCoinsReqDTO) {
        List<UserAccount> userAccounts = this.userAccountMapperExt.queryExchangeAccountByUserId(updateSupportCoinsReqDTO.getUserId(), ExchangeTypeEnum.HUOBI.code, AccountBizTypeEnum.CONSTRACT_TRADE.getCode());
        if (userAccounts.size()!=1){
            log.info(">>>>> 修改支持币种,发现绑定多个(非1个)HUOBI账户,数据为:{}<<<<<",JSON.toJSONString(userAccounts));
            throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
        }
        UserAccount userAccount = userAccounts.get(0);
        String accountId = userAccount.getAccountId();
        if (!updateSupportCoinsReqDTO.getAccountId().equals(accountId)){
            log.info(">>>>> 修改支持币种,解绑传入accountId与该用户传入id不符,数据为reqDTO accountId:{}, userAccount accountId:{}<<<<<",updateSupportCoinsReqDTO.getAccountId(),accountId);
            throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
        }

        //修改当前支持币种时判断是否有取消该币种的持仓
        String coins = updateSupportCoinsReqDTO.getCoins();
        //原本支持的币种
        String supportCoins = userAccount.getSupportCoins();
        String[] split = supportCoins.split(",");
        //获取原本支持现在不支持币种
        List<String> removeCoins= new ArrayList<>();
        for (String coin: split){
            if(!coins.contains(coin)){
                removeCoins.add(coin);
            }
        }

        List<String> positionCoins = this.userAccountMapperExt.getAccountPositionCoin(accountId);
        for (String coin: positionCoins){
            //如果持仓币种包含需要移除币种则报错
            if (removeCoins.contains(coin)){
                log.info(">>>>>移除币种时该币种正在持仓,该币种为:{}<<<<<",coin);
                throw new BaseBizException(ResponseStatusEnum.POSITION_ERROR);

            }
        }

        UserAccount u = new UserAccount();
        u.setSupportCoins(updateSupportCoinsReqDTO.getCoins());
        u.setModifyTime(new Date());
        u.setId(userAccount.getId());

        //对账户进行逻辑删除
        int rs= this.userAccountMapper.updateByPrimaryKeySelective(u);
        if (rs <=0) {
            log.info(">>>>> 修改支持币种，userAccountMapper.updateByPrimaryKeySelective错误 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
        }

        return true;
    }

    @Override
    public GetApiInfoRespVO getApiInfo(GetApiInfoReqDTO getApiInfoReqDTO) {
        UserAccount userAccount = this.userAccountMapperExt.queryByAccountId(getApiInfoReqDTO.getAccountId());
        if (userAccount==null || !userAccount.getUserId().equalsIgnoreCase(getApiInfoReqDTO.getUserId())){
            log.error(">>>>> 获取api信息，accountId为:{},不是该用userId为:{}下的账户错误 <<<<<",getApiInfoReqDTO.getAccountId(),getApiInfoReqDTO.getUserId());
            throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
        }
        GetApiInfoRespVO apiInfo = this.userAccountMapperExt.getApiInfo(getApiInfoReqDTO.getAccountId());
        return apiInfo;
    }

    @Override
    public GetSupportCoinsRespVO getSupportCoins(GetSupportCoinsReqDTO getSupportCoinsReqDTO) {
        UserAccount userAccount = this.userAccountMapperExt.queryByAccountId(getSupportCoinsReqDTO.getAccountId());
        if (!userAccount.getUserId().equalsIgnoreCase(getSupportCoinsReqDTO.getUserId())){
            log.error(">>>>> 获取支持币种出错，accountId不是该用userId下的账户错误 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
        }

        GetSupportCoinsRespVO respVO = new GetSupportCoinsRespVO();
        respVO.setCoins(userAccount.getSupportCoins());
        return respVO;
    }


    @Override
    public List<GetExchangeSupportCoinsRespDTO> getExchangeSupportCoins(GetExchangeSupportCoinsReqDTO getApiInfoReqDTO) {
        List<String> coins = this.userExchangePwdMapperExt.queryExchangeCoins(getApiInfoReqDTO.getExchangeType(), getApiInfoReqDTO.getBizType());
        String accountId = getApiInfoReqDTO.getAccountId();

        String supportCoins = "";
        if (StringUtils.isNotEmpty(accountId)){
            UserAccount userAccount = this.userAccountMapperExt.queryByAccountId(accountId);
            if (userAccount==null){
                log.error(">>>>> 获取交易所支持币种出错，accountId不存在错误 <<<<<");
                throw new BaseBizException(ResponseStatusEnum.DATA_OPERATE_FAIL);
            }
            supportCoins = userAccount.getSupportCoins();
        }

        List<GetExchangeSupportCoinsRespDTO> respDTOS = new ArrayList<>();
        for (String c: coins){
            GetExchangeSupportCoinsRespDTO respDTO = new GetExchangeSupportCoinsRespDTO();
            respDTO.setCoin(c);
            if (supportCoins.contains(c)){
                respDTO.setSupport(true);
            }else {
                respDTO.setSupport(false);
            }
            respDTOS.add(respDTO);

        }

        return respDTOS;
    }

}
